#pragma once

#include <iostream>
#include <string>
#include<vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <atomic>
#include <fstream>
#include <boost/algorithm/string.hpp>

namespace ns_util
{
    /*1.公共模块->文件后缀名路添加*/
    class path_util
    {
    public:
        /*
         * filename->
         * ./temp/filename.cpp
         * ./temp/filename.exe
         * ./temp/filename.stderr
         */
        static std::string AddSuffix(const std::string &filename, const std::string &tail)
        {
            std::string new_filename = "./temp/";
            new_filename += filename;
            new_filename += tail;
            return new_filename;
        }

        /*编译时需要的临时文件*/
        static std::string src_cpp(const std::string &filename)
        {
            return AddSuffix(filename, ".cpp");
        }
        static std::string dest_exe(const std::string &filename)
        {
            return AddSuffix(filename, ".exe");
        }
        static std::string compiler_err(const std::string &filename)
        {
            return AddSuffix(filename, ".compile_error");
        }

        /*运行时需要的临时文件*/
        static std::string std_in(const std::string &filename)
        {
            return AddSuffix(filename, ".stdin");
        }
        static std::string std_out(const std::string &filename)
        {
            return AddSuffix(filename, ".stdout");
        }
        static std::string std_err(const std::string &filename)
        {
            return AddSuffix(filename, ".stderr");
        }
    };

    /*2.公共模块->时间获取*/
    class time_util
    {
    public:
        /**************************
        struct tm
        {
            int tm_sec;
            int tm_min;
            int tm_hour;
            int tm_mday;
            int tm_mon;
            int tm_year;
            int tm_wday;
            int tm_yday;
            int tm_isdst;
        };
        struct tm *local;
        time_t t;
        t=time(NULL);
        local=localtime(&t);
        ***************************/
        static std::string get_time(int select)
        {
            time_t t;
            t = time(NULL);
            switch (select)
            {
            case 1:
                return ctime(&t);
                break;
            case 2:
                return std::to_string(t);
                break;
            case 3:
                return std::to_string(t * 1000 + t / 1000);
                break;
            }
        }
    };

    /*3.公共模块->判断.exe是否存在，即编译模块中子进程是否编译成功*/
    class file_util
    {
        typedef struct stat ret_type;

    public:
        static bool is_file_exists(const std::string &pathname)
        {
            ret_type st;
            if (stat(pathname.c_str(), &st) == 0)
            {
                return true;
            }
            return false;
        }

    public:
        /*毫秒级时间戳+原子性递增唯一值->保证唯一性*/
        static std::string unique_file_name()
        {
            std::string ms = time_util::get_time(3);
            static std::atomic_uint id(0);
            id++;
            std::string unique_id = std::to_string(id);
            return ms + "-" + unique_id;
        }

    public:
        static bool write_file(const std::string &target, const std::string &code)
        {
            std::ofstream out(target);
            if (!out.is_open())
            {
                return false;
            }
            out.write(code.c_str(), code.size());
            out.close();
            return true;
        }

    public:
        static bool read_file(const std::string &target, std::string *code, bool keep = false)
        {
            (*code).clear();
            std::ifstream in(target);
            if (!in.is_open())
            {
                return false;
            }
            std::string line;
            while (std::getline(in, line))
            {
                (*code) += line;
                (*code) += (keep ? "\n" : "");
            }
            in.close();
            return true;
        }
    };

    class string_util
    {
    public:
        static void splitstring(const std::string &line, std::vector<std::string> *tokens, const std::string &c)
        {
            boost::split((*tokens), line, boost::is_any_of(c), boost::algorithm::token_compress_on);
        }
    };
}